package jrain.fw.httpclient.base;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import jrain.fw.core.http.HttpClientService;
import jrain.fw.core.http.HttpContentFormatType;
import jrain.fw.core.http.HttpMethod;
import jrain.fw.core.http.HttpRequest;
import jrain.fw.core.http.HttpResponse;
import jrain.fw.core.service.DestroyService;
import jrain.fw.core.service.InitService;
import jrain.fw.core.service.Service;
import jrain.fw.core.service.ServiceConst;

@Service(name = "base", group = ServiceConst.S_HTTP_CLIENT_SERVICE, module = ServiceConst.M_HTTP_CLIENT)
public class HttpClientBaseService implements HttpClientService, InitService, DestroyService {

	@Override
	public void destroy() {

	}

	@Override
	public void init() {

	}

	@Override
	public HttpResponse doInvoke(HttpRequest request) {
		OutputStream out = null;
		InputStream content = null;
		HttpURLConnection httpConn = null;
		try {
			httpConn = getHttpConnection(request);
			httpConn.connect();
			byte contents[] = getHttpConent(request);
			if (contents != null && contents.length > 0) {
				out = httpConn.getOutputStream();
				out.write(contents);
			}
			content = httpConn.getInputStream();
			HttpResponse response = new HttpResponse();
			request.setUrl(httpConn.getURL().toString());
			pasrseHttpConn(response, httpConn, content);
			return response;
		} catch (IOException e) {
			content = httpConn.getErrorStream();
			HttpResponse response = new HttpResponse();
			response.setStatus(500);
			request.setUrl(httpConn.getURL().toString());
			try {
				pasrseHttpConn(response, httpConn, content);
			} catch (IOException e1) {
			}
			return response;
		} finally {
			if (content != null) {
				try {
					content.close();
				} catch (IOException e) {
				}
			}
			if (httpConn != null) {
				httpConn.disconnect();
			}
		}
	}

	public HttpURLConnection getHttpConnection(HttpRequest request) throws IOException {

		// 设置请求地址
		String strUrl = request.getUrl();
		HttpMethod httpMethod = request.getMethod();
		if (null == strUrl || null == httpMethod) {
			return null;
		}
		URL url = null;
		String[] urlArray = null;
		if (HttpMethod.POST.equals(httpMethod)) {
			urlArray = strUrl.split("\\?");
			url = new URL(urlArray[0]);
		} else {
			url = new URL(strUrl);
		}
		// 设置请求类型
		System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
		HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
		httpConn.setRequestMethod(request.getMethod().name());
		httpConn.setDoOutput(true);
		httpConn.setDoInput(true);
		httpConn.setUseCaches(false);
		// 设置连接的超时时间
		if (request.getConnectTimeout() > 0) {
			httpConn.setConnectTimeout(request.getConnectTimeout());
		}
		// 设置读取的超时时间
		if (request.getReadTimeout() > 0) {
			httpConn.setReadTimeout(request.getReadTimeout());
		}
		// 设置请求头
		Map<String, String> mappedHeaders = request.getHeader();
		for (Entry<String, String> entry : mappedHeaders.entrySet()) {
			httpConn.setRequestProperty(entry.getKey(), entry.getValue());
		}
		// 设置请求内容格式
		if (null != request.getHeader(HttpRequest.CONTENT_TYPE)) {
			httpConn.setRequestProperty(HttpRequest.CONTENT_TYPE, request.getHeader(HttpRequest.CONTENT_TYPE));
		} else {
			String contentTypeValue = request.getContentTypeValue(request.getHttpContentType(), request.getEncoding());
			if (null != contentTypeValue) {
				httpConn.setRequestProperty(HttpRequest.CONTENT_TYPE, contentTypeValue);
			}
		}
		// 设置请求内容
		if (HttpMethod.POST.equals(request.getMethod()) && null != urlArray && urlArray.length == 2) {
			httpConn.getOutputStream().write(urlArray[1].getBytes());
		}
		return httpConn;
	}

	public byte[] getHttpConent(HttpRequest request) {
		byte[] bytes = request.getContent();
		if (bytes == null) {
			bytes = getFormData(request.getData());
		}
		return bytes;
	}

	public byte[] getFormData(Map<String, Object> params) {
		try {
			StringBuilder result = new StringBuilder();
			boolean first = true;
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				if (first) {
					first = false;
				} else {
					result.append("&");
				}
				result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
				result.append("=");
				if (entry.getValue() != null) {
					result.append(URLEncoder.encode(entry.getValue().toString(), "UTF-8"));
				}
			}
			return result.toString().getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	private static byte[] readContent(InputStream content) throws IOException {
		if (content == null) {
			return null;
		}
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		byte[] buff = new byte[1024];

		while (true) {
			final int read = content.read(buff);
			if (read == -1) {
				break;
			}
			outputStream.write(buff, 0, read);
		}

		return outputStream.toByteArray();
	}

	private static void pasrseHttpConn(HttpResponse response, HttpURLConnection httpConn, InputStream content) throws IOException {
		byte[] buff = readContent(content);
		// 响应状态
		response.setStatus(httpConn.getResponseCode());
		// 响应头
		Map<String, List<String>> headers = httpConn.getHeaderFields();
		for (Entry<String, List<String>> entry : headers.entrySet()) {
			String key = entry.getKey();
			if (null == key) {
				continue;
			}
			List<String> values = entry.getValue();
			StringBuilder builder = new StringBuilder(values.get(0));
			for (int i = 1; i < values.size(); i++) {
				builder.append(",");
				builder.append(values.get(i));
			}
			response.putHeader(key, builder.toString());
		}
		// 响应格式与内容编码
		String type = response.getHeader(HttpResponse.CONTENT_TYPE);
		if (null != buff && null != type) {
			response.setEncoding("UTF-8");
			String[] split = type.split(";");
			response.setHttpContentType(HttpContentFormatType.mapAcceptToFormat(split[0].trim()));
			if (split.length > 1 && split[1].contains("=")) {
				String[] codings = split[1].split("=");
				response.setEncoding(codings[1].trim().toUpperCase());
			}
		}
		// 设置响应内容
		response.setContents(buff);
	}
}
